﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Windows.Forms.Design;
using System.Collections;
using System.Runtime.InteropServices;


namespace TH10_Dat_Tools
{
    /// <summary>
    /// 打包类
    /// </summary>
    public class PackFiles
    {

        /// <summary>
        /// 将指定目录下的文件打包成Dat文件
        /// </summary>
        /// <param name="DatFileName">目标Dat文件</param>
        /// <param name="DirPath">源目录</param>
        public static void Pack(string DatFileName, string DirPath)
        {
            byte[] buff;
            byte[] tmp;
            string[] f = Directory.GetFiles(DirPath);
            int file_point;
            //获得要打包的文件列表
            FileInfo[] files = new FileInfo[f.Length];
            for (int i = 0; i < files.Length; i++)
            {
                files[i] = new FileInfo(f[i]);
            }

            //生成密钥组
            int KeyID;//密钥编号
            Key[] keys = new Key[8];//密钥组
            int[] k ={
                0x1b, 0x37, 0x40,  0x2800,
	            0x51, 0xe9, 0x40,  0x3000,
	            0xc1, 0x51, 0x80,  0x3200,
	            0x03, 0x19, 0x400, 0x7800,
	            0xab, 0xcd, 0x200, 0x2800,
	            0x12, 0x34, 0x80,  0x3200,
	            0x35, 0x97, 0x80,  0x2800,
	            0x99, 0x37, 0x400, 0x2000
            };
            for (int i = 0; i < 8; i++)
            {
                keys[i] = new Key();
                keys[i].k1 = (byte)k[4 * i + 0];
                keys[i].k2 = (byte)k[4 * i + 1];
                keys[i].block = k[4 * i + 2];
                keys[i].limit = k[4 * i + 3];
            }

            //生成文件头
            TH_Head hd = new TH_Head();
            hd.numOfEntry = files.Length;
            hd.Flag = "THA1";

            //
            TH_Entry[] TH_Files = new TH_Entry[files.Length];


            FileStream fs = new FileStream(DatFileName, FileMode.Create, FileAccess.Write);
            BinaryWriter bw = new BinaryWriter(fs);

            //预填充
            bw.Write(0);
            bw.Write(0);
            bw.Write(0);
            bw.Write(0);

            file_point = 0x10;
            //打包文件，写入数据段
            for (int i = 0; i < files.Length; i++)
            {
                //填写索引结构
                TH_Files[i] = new TH_Entry();
                TH_Files[i].FileName = files[i].Name;
                TH_Files[i].orgSize = (int)files[i].Length;
                TH_Files[i].offset = file_point;

                file_point += (int)files[i].Length;

                //读入源数据
                FileStream fs_in = new FileStream(files[i].FullName, FileMode.Open, FileAccess.Read);
                BinaryReader br = new BinaryReader(fs_in);
                buff = br.ReadBytes((int)fs_in.Length);
                br.Close();
                fs_in.Close();

                //计算密钥组编号
                KeyID = Tools.GetKeyID(files[i].Name);

                //压缩数据
                /*暂时不用
                buff = Tools.TH_Lzss(buff);
                */
                
                //加密数据
                buff = Tools.TH_Crypter(buff, keys[KeyID].k1, keys[KeyID].k2, keys[KeyID].block, keys[KeyID].limit);

                //写入磁盘
                bw.Write(buff);
            }

            //生成索引段
            buff = null;
            for (int i = 0; i < files.Length; i++)
            {
                //文件名
                tmp = Encoding.Default.GetBytes(files[i].Name);
                buff = Tools.ByteAdd(buff, tmp);
                
                //填充成4倍字节长度
                tmp = new byte[4 - (tmp.Length % 4)];
                for (int x = 0; x < tmp.Length; x++)
                {
                    tmp[x] = 0x00;
                }
                buff = Tools.ByteAdd(buff, tmp);

                //偏移量
                tmp=new byte[4];
                Marshal.WriteInt32(tmp, 0, TH_Files[i].offset);
                buff = Tools.ByteAdd(buff, tmp);

                //数据原大小
                Marshal.WriteInt32(tmp, 0, TH_Files[i].orgSize);
                buff = Tools.ByteAdd(buff, tmp);

                //填充
                Marshal.WriteInt32(tmp, 0, 0);
                buff = Tools.ByteAdd(buff, tmp);
            }

            //记录索引段原大小
            hd.originalSizeOfEntries = buff.Length;

            //压缩索引段
            buff = Tools.TH_Lzss(buff);

            //记录索引段压缩后大小
            hd.compressedSizeofEntries = buff.Length;

            //加密索引段
            buff = Tools.TH_Crypter(buff, 0x3E, 0x9B, 0x80, buff.Length);

            //索引段写入磁盘
            bw.Write(buff);

            //准备生成文件头
            buff = null;
            buff = Tools.ByteAdd(buff, Encoding.Default.GetBytes(hd.Flag));
            
            //第一次加密
            hd.originalSizeOfEntries += 123456789;
            hd.compressedSizeofEntries += 987654321;
            hd.numOfEntry += 135792468;
            
            tmp = new byte[4];
            Marshal.WriteInt32(tmp, 0, hd.originalSizeOfEntries);
            buff = Tools.ByteAdd(buff, tmp);

            Marshal.WriteInt32(tmp, 0, hd.compressedSizeofEntries);
            buff = Tools.ByteAdd(buff, tmp);

            Marshal.WriteInt32(tmp, 0, hd.numOfEntry);
            buff = Tools.ByteAdd(buff, tmp);

            //第2次加密文件头
            buff = Tools.TH_Crypter(buff, 0x1B, 0x37, 0x10, 0x10);

            //头部写入磁盘,关闭文件流
            fs.Seek(0, SeekOrigin.Begin);
            bw.Write(buff);
            bw.Close();
            fs.Close();
        }
    }
}